home *** CD-ROM | disk | FTP | other *** search
/ PC-Blue - MS DOS Public Domain Library / PC-Blue MS-DOS Public Domain Library - NYACC.iso / vol194 / kermasm.arc / MSKERM.ASM < prev    next >
Encoding:
Assembly Source File  |  1985-11-14  |  39.8 KB  |  1,646 lines

  1. ; Edit history:
  2.  
  3. ; [v2.28]
  4. ; Made RUN handle batch files
  5. ; When calling command parser for directory, etc., use correct switch char
  6. ;    (from by Tony Movshon, NYU)
  7. ; JD  15 May 1985
  8.  
  9.     public    prompt, dosnum, curdsk, fpush, isfile, malloc
  10.     include msdefs.h
  11. ;******************** Version 2.27 ********************************** 
  12. ; KERMIT, Celtic for "free" 
  13. ;
  14. ; The name "Kermit" is a registered trade mark of Henson Associates, Inc.,
  15. ; used by permission.
  16. ;       Kermit-MS Program Version 2.27, December 6,1984
  17. ;       Based on the Columbia University KERMIT Protocol.
  18. ;       Copyright (C) 1982,1983,1984 Trustees of Columbia University
  19. ;
  20. ;       Daphne Tzoar, Jeff Damens
  21. ;       Columbia University Center for Computing Activities
  22. ;       612 West 115th Street
  23. ;       New York, NY  10025
  24. ; Special thanks to Frank da Cruz, Bill Catchings, Steve Jensen, Herm Fischer,
  25. ; Vace Kundakci, and Bernie Eiben for their help and contributions.
  26.  
  27. makseg    equ    26H
  28. deffcb    equ    5cH
  29. exec    equ    4BH
  30. env    equ    2CH        ; environment address in psp
  31. terma    equ    10        ; termination address in psp
  32. cline    equ    80H        ; offset in psp of command line
  33. namsiz    equ    65        ; Bytes for file name and size.
  34. maxnam    equ    10
  35. chmod    equ    43H        ; chmod call (used to test for file existence)
  36.  
  37. STACK   SEGMENT PARA STACK 'STACK'
  38.         DW      100 DUP(0)      ; Initialize stack to all zeros.
  39. STK    EQU    THIS WORD
  40. STACK   ENDS
  41.  
  42. datas   segment public 'datas'
  43.     extrn    buff:byte, comand:byte, flags:byte, pack:byte, trans:byte
  44.     extrn    fcb:byte, cpfcb:byte, prmptr:word, inichk:byte
  45.     extrn    machnam:byte, msfinal:byte
  46.     public    takadr,taklev
  47.  
  48. versio    label    byte
  49.     verdef
  50.     db    cr,lf
  51.     db    '$'
  52. hlpmsg    db    'Type ? for help',cr,lf
  53.     db    '$'
  54.  
  55. tmp    db    ?,'$'
  56. crlf    db      cr,lf,'$'
  57. ermes1  db      cr,lf,'?Unrecognized command$'
  58. ermes2    db    cr,lf,'?Unable to initialize memory$'
  59. ermes3  db      cr,lf,'?Not confirmed$'
  60. ermes4    db    cr,lf,'?Unable to change directory$'
  61. erms30    db    cr,lf,'Passed maximum nesting level for TAKE command$'
  62. erms31    db    cr,lf,'Take file not found$'
  63. erms32    db    cr,lf,'File(s) not found$'
  64. erms33    db    cr,lf,'CHKDSK program not found on current disk$'
  65. erms34    db    cr,lf,'This command works only for DOS 2.0 and above$'
  66. erms35    db    cr,lf,'Must specify program name$'
  67. erms36    db    cr,lf,'Could not free memory$'
  68. erms37    db    cr,lf,'Unable to execute program$'
  69. infms1    db    'Really erase *.*? $'
  70. infms8    db    cr,lf,'File(s) erased$'
  71. tmsg5    db    cr,lf,'[closing log file]',cr,lf,'$' ; [jd]
  72. filhlp1 db      ' Command file specification $'
  73. filhlp2 db      ' File specification (possibly wild) $'
  74. filhlp3    db    ' File spec (possibly wild) or confirm with carriage return$'
  75. filmsg    db    ' File specification with optional path name $'
  76. filwmsg    db    ' File specification (possibly wild) with optional path name $'
  77. pmsg    db    ' Path to connect to$'
  78. chkfil    db    0,'CHKDSK  COM'
  79. chkflen    equ    $-chkfil
  80.  
  81. tophlp    db    cr,lf
  82.     db    'BYE            '
  83.     db    'CLEAR          '
  84.     db    'CLOSE          '
  85.     db      'CONNECT        '
  86.     db    cr,lf
  87.     db    'CWD            '
  88.     db    'DEFINE         '
  89.     db    'DELETE         '
  90.     db    'DIRECTORY      '
  91.     db    cr,lf
  92.     db    'DO             '
  93.         db      'EXIT           '
  94.     db    'FINISH         '
  95.     db    'GET            '
  96.     db    cr,lf
  97.         db      'HELP           '
  98.     db    'LOCAL          '
  99.     db    'LOG            '
  100.     db    'LOGOUT         '
  101.     db    cr,lf
  102.     db    'PUSH           '
  103.         db      'QUIT           '
  104.         db      'RECEIVE        '
  105.     db    'REMOTE         '
  106.     db    cr,lf
  107.     db    'RUN            '
  108.         db      'SEND           '
  109.     db    'SERVER         '
  110.         db      'SET            '
  111.     db    cr,lf
  112.     db    'SHOW           '
  113.     db    'SPACE          '
  114.         db      'STATUS         '
  115.     db    'TAKE           '
  116.     db    cr,lf
  117.     db    'TYPE           '
  118.     db    'VERSION        '
  119.     db    cr,lf,'$'
  120.  
  121. lochlp    db    cr,lf,'CWD path'
  122.     db    cr,lf,'DELETE file'
  123.     db    cr,lf,'DIRECTORY [filespec]'
  124.     db    cr,lf,'SPACE remaining on current disk'
  125.     db    cr,lf,'RUN program'
  126.     db    cr,lf,'PUSH to command interpreter'
  127.     db    cr,lf,'TYPE local file'
  128.     db    '$'
  129.  
  130.         ; COMND tables
  131.  
  132. yestab    db    2
  133.     mkeyw    'NO',0
  134.     mkeyw    'YES',1
  135.  
  136. comtab  db    31
  137.     mkeyw    'BYE',bye
  138.     mkeyw    'C',telnet
  139.     mkeyw    'CLEAR',clear
  140.     mkeyw    'CLOSE',clscpt
  141.     mkeyw    'CONNECT',telnet
  142.     mkeyw    'CWD',cwd
  143.     mkeyw    'DEFINE',dodef
  144.     mkeyw    'DELETE',delete
  145.     mkeyw    'DIRECTORY',direct
  146.     mkeyw    'DO',docom
  147.     mkeyw    'EXIT',exit
  148.     mkeyw    'FINISH',finish
  149.     mkeyw    'GET',get
  150.     mkeyw    'HELP',help
  151.     mkeyw    'LOCAL',lclcmd
  152.     mkeyw    'LOG',setcpt
  153.     mkeyw    'LOGOUT',logout
  154.     mkeyw    'PUSH',dopush
  155.     mkeyw    'QUIT',exit
  156.     mkeyw    'RECEIVE',read
  157.     mkeyw    'REMOTE',remote
  158.     mkeyw    'RUN',run
  159.     mkeyw    'SEND',send
  160.     mkeyw    'SERVER',server
  161.     mkeyw    'SET',setcom
  162.     mkeyw    'SHOW',showcmd
  163.     mkeyw    'SPACE',chkdsk
  164.     mkeyw    'STATUS',status
  165.     mkeyw    'TAKE',take
  166.     mkeyw    'TYPE',typec
  167.     mkeyw    'VERSION',prvers
  168.  
  169. loctab    db    7
  170.     mkeyw    'CWD',cwd
  171.     mkeyw    'DELETE',delete
  172.     mkeyw    'DIRECTORY',direct
  173.     mkeyw    'PUSH',dopush
  174.     mkeyw    'RUN',run
  175.     mkeyw    'SPACE',chkdsk
  176.     mkeyw    'TYPE',typec
  177.  
  178. shotab    db    2
  179.     mkeyw    'KEY',shokey
  180.     mkeyw    'MACROS',shomac
  181.  
  182. ; Program storage.
  183.  
  184. oldstk  dw      ?               ; Storage for system stack.
  185. oldsts  dw      ?               ; System stack segment.
  186. ssave    dw    ?        ; Original SS when doing CHKDSK.
  187. siz    dw    ?        ; Memory size.
  188. in3ad    dd    0        ; Original break interrupt addresses. [25]
  189. curdsk    db    0        ; Current disk. 
  190. origd    db    0        ; Original disk.
  191. fildat    db    0        ; Manipulate file data/time creation.
  192.     db    0
  193. taklev    db    0        ; Take levels. [25t]
  194. takadr    dw    takstr-(size takinfo) ; Pointer into structure. [25t]
  195. temp    dw    0
  196. temp1   dw      ?               ; Temporary storage.
  197. temp2   dw      ?
  198. temp3   dw      ?
  199. temp4   dw      ?
  200. psp    dw    ?
  201. divst    dw    0    
  202. takstr    db    (size takinfo) * maxtak dup(?)
  203. ininam    db    0,'MSKERMITINI'    ; init file name, on default disk, 12 chars
  204. ininm2    db    'MSKERMIT.INI',0 ; init file name for 2.0
  205. nambuf    db    maxnam * namsiz dup (?)
  206. cmdnam    db    namsiz dup (?)
  207. exefcb    db    fcbsiz dup (?)
  208. exefcb2    db    fcbsiz dup (?)
  209. exearg    dw    ?        ; segment addr of environment (filled in below)
  210.     dd    0        ; ptr to cmd line (filled in below)
  211.     dd    exefcb        ; default fcb
  212.     dd    exefcb2        ; second default fcb
  213. dircmd    db    ' '
  214. dirswt    db    '/'
  215.     db    'c dir '
  216. dirclen    equ    $-dircmd
  217. dirnam    db    50h dup (?)
  218. chkdcmd    db    'chkdsk.com'
  219. chkdlen    equ    $-chkdcmd
  220. typcmd    db    'c type '
  221. typclen    equ    $-typcmd
  222. dosnum    db    ?        ; dos version number
  223. pthnam    db    'PATH='
  224. pthlen    equ    $-pthnam
  225. pthbuf    db    100 dup (?)    ; buffer for path definition.
  226. defpth    db    '\', 70 dup (?)    ; buffer for default path
  227. slashc    db    ' '
  228. slswit    db    '/'
  229.     db    'c '
  230. slslen    equ    $-slashc
  231. batnam    db    'BAT'
  232. batbuf    db    100 dup (?)
  233. cmspnam    db    'COMSPEC='
  234. cmsplen    equ    $-cmspnam
  235. cmspbuf    db    '\command.com',0 ; default name
  236.     db    30 dup (?)    ; some additional space
  237. tfile    db    100 dup (?)    ; temp space for file names.
  238. eexit    db    cr,'exit',cr
  239. leexit    equ    $-eexit
  240. mfmsg    db    '?Not enough memory to run Kermit$'
  241. datas   ends                    ; End data segment
  242.  
  243. code    segment    public 
  244.     public    takrd
  245. start   proc  far
  246.     extrn    cmblnk:near, locate:near, logout:near
  247.     extrn    bye:near, telnet:near, finish:near, comnd:near
  248.     extrn    read:near, remote:near, send:near, status:near, get:near
  249.     extrn    dodisk:near, serrst:near, setcom:near
  250.     extrn    clscpi:near, clscpt:near, getbaud:near
  251.     extrn    dodef:near, setcpt:near, docom:near
  252.     extrn    server:near, lclini:near, shokey:near, shomac:near
  253.     extrn    packlen:near, clrdef:near
  254.         assume  cs:code,ds:datas,ss:stack,es:nothing
  255.  
  256.         push ds                 ; Save system data area.
  257.         sub ax,ax               ; Get a zero.
  258.         push ax                 ; Put zero return addr on stack.
  259.  
  260.     mov ax,datas           ; Initialize DS.
  261.         mov ds,ax
  262.     sub ax,ax
  263.  
  264.         mov oldstk,sp           ; Save old stack pointer.
  265.  
  266.     mov ax,es:[2]        ; In program segment prefix
  267.     mov siz,ax        ; Pick up memory size
  268.     mov psp,es    
  269.  
  270.     mov ah,prstr
  271.     mov dx,offset machnam    ; print machine name
  272.     int dos
  273.         mov ah,prstr            ; Print the version header.
  274.         mov dx,offset versio
  275.         int dos
  276.     mov ah,prstr
  277.     mov dx,offset hlpmsg
  278.     int dos
  279.  
  280.     mov ah,setdma        ; Set disk transfer address.
  281.     mov dx,offset buff
  282.     int dos
  283.  
  284.     call getbaud        ; Get the baud rate.
  285.     call dodisk        ; See how many disk drives we have.
  286.     call setint
  287.     mov ah,gcurdsk        ; Get current disk.
  288.     int dos
  289.     inc al            ; We want 1 == A (not zero).
  290.     mov curdsk,al
  291.     mov origd,al        ; Remember original disk we started on.
  292.     mov ah,dosver
  293.     int dos
  294.     mov dosnum,al        ; remember dos version
  295.     mov es,psp
  296.     mov ax,es:[env]        ; pick up environment address
  297.     push ax
  298.     call getpath        ; get the path from the environment
  299.     pop ax            ; get environment back
  300.     call getcsp        ; get comspec from environment as well
  301.     call memini        ; init our memory usage
  302.     call lclini        ; do local initialization
  303.     call gcmdlin        ; read command line
  304.     call rdinit        ; read kermit init file
  305.     call packlen        ; Packet length in case do server comand.
  306.     mov ah,gswitch
  307.     mov al,0        ; pick up switch character
  308.     int dos
  309.     mov slswit,dl
  310.     mov dirswt,dl        ; save where we need it...
  311.  
  312. ; This is the main KERMIT loop.  It prompts for and gets the users commands.
  313.  
  314. kermit:    mov ax,ds
  315.     mov es,ax        ; make sure this addresses data segment
  316.     mov dx,prmptr        ; get prompt
  317.     call prompt             ; Prompt the user.
  318.     mov pack.state,0    ; Clear the state.
  319.     mov flags.cxzflg,0    ; Reset each itme.
  320.     mov ah,inichk        ; Original or set checksum length.
  321.     mov trans.chklen,ah    ; Reset just in case.
  322.         mov dx,offset comtab
  323.         mov bx,offset tophlp
  324.     mov comand.cmcr,1    ; Allow bare CR's.
  325.         mov ah,cmkey
  326.         call comnd
  327.          jmp kermt2
  328.     mov comand.cmcr,0    ; Not anymore.
  329.         call bx                 ; Call the routine returned.
  330.          jmp kermt3
  331.     cmp flags.extflg,0    ;  Check if the exit flag is set.
  332.     jne krmend        ;  If so jump to KRMEND.
  333.     jmp kermit        ; Do it again.
  334.  
  335. kermt2:    mov dx,offset ermes1    ;  Give an error.
  336.     jmp short kermt4
  337.  
  338. kermt3:    mov dx,offset ermes3    ;  Give an error.
  339. kermt4:    cmp flags.cxzflg,'C'    ; some sort of abort?
  340.     je kermit        ; yes, don't print error message.
  341.     mov ah,prstr
  342.     int dos
  343.     mov flags.droflg,0    ; Reset drive override flag.
  344.     mov flags.nmoflg,0    ; Reset filename override flag.
  345.     mov flags.getflg,0    ; May as well do this one.
  346.     mov flags.cmrflg,0    ; This one too.
  347.     jmp kermit
  348.  
  349. krmend: call serrst        ; Just in case the port wasn't reset. [21c] 
  350.     mov dl,origd        ; Original disk drive.
  351.     dec dl            ; Want A == 0.
  352.     mov ah,seldsk        ; Reset original disk just in case.
  353.     int dos
  354.     mov sp,oldstk
  355.     ret
  356.  
  357. START    ENDP
  358.  
  359. ; change working directory
  360. cwd    proc    near
  361.     mov    ah,cmtxt
  362.     mov    bx,offset tfile
  363.     mov    dx,offset pmsg
  364.     call    comnd
  365.      jmp    r
  366.     mov    bl,ah
  367.     mov    bh,0
  368.     mov    byte ptr tfile[bx],0    ; tie off the string
  369.     mov    dx,offset tfile
  370.     mov    ah,chdir
  371.     int    dos
  372.     jnc    cwd1
  373.     mov    dx,offset ermes4
  374.     mov    ah,prstr
  375.     int    dos
  376. cwd1:    jmp    rskp
  377. cwd    endp
  378.  
  379. ; clear macro definitions
  380. clear    proc    near
  381.     mov    ah,cmcfm
  382.     call    comnd
  383.      jmp    r
  384.     call    clrdef
  385.     jmp    rskp
  386. clear    endp
  387.  
  388. ; This is the 'exit' command.  It leaves KERMIT and returns to DOS.
  389.  
  390. EXIT    PROC    NEAR
  391.     mov ah,cmcfm
  392.     call comnd        ; Get a confirm.
  393.      jmp r
  394.     test    flags.capflg,0FFH    ; capturing?
  395.     jz    exit1            ; no, keep going
  396.     mov    dx,offset tmsg5
  397.     mov    ah,prstr
  398.     int    dos
  399.     call    clscpi
  400.      nop                ; this skip returns...
  401.      nop
  402.      nop
  403. exit1:
  404.     mov flags.extflg,1    ;  Set the exit flag.
  405.     jmp rskp        ; Then return to system.
  406. EXIT    ENDP
  407.  
  408.  
  409. ; This is the 'help' command.  It gives a list of the commands.
  410.  
  411. HELP    PROC    NEAR
  412.     mov ah,cmcfm
  413.     call comnd        ; Get a confirm.
  414.      jmp r
  415.     mov ah,prstr        ; Print a string to the console.
  416.     mov dx,offset tophlp    ; The address of the help message.
  417.     int dos
  418.     jmp rskp
  419. HELP    ENDP
  420.  
  421. lclcmd    proc    near
  422.     mov ah,cmkey
  423.     mov dx,offset loctab
  424.     mov bx,offset lochlp
  425.     call comnd
  426.      jmp r
  427.     call bx
  428.     nop
  429.     nop
  430.     nop
  431.     jmp rskp
  432. lclcmd    endp
  433.  
  434. ; Don't ignore ¬C when in debug mode.
  435. SETINT    PROC    NEAR
  436.     push ds            ; Don't forget this. [25]
  437.     mov ax,ds
  438.     mov es,ax        ; So can access our data area.
  439.     mov ax,0
  440.     mov ds,ax        ; Access low core.
  441.     mov ax,ds:[23H * 4]    ; Address for interrupt 23H.
  442.     mov cx,ds:[23H * 4 +2]    ; CS value for it.
  443.     mov word ptr es:in3ad,ax ; Remember original values.
  444.     mov word ptr es:in3ad+2,cx
  445.     mov ax,cs
  446.     mov ds,ax        ; Access code are.
  447.     mov dx,offset intbrk
  448.     mov al,23H        ; On ¬C, goto above address.
  449.     mov ah,25H
  450.     int dos
  451.     pop ds
  452.     ret
  453. SETINT    ENDP
  454.  
  455. ; take commands from a file, but allow a path name
  456. PTAKE    PROC    NEAR
  457.     cmp taklev,maxtak        ; Hit our limit?
  458.     jl ptake1            ; Continue if still OK.
  459.     mov ah,prstr
  460.     mov dx,offset erms30        ; Complain.
  461.     int dos 
  462.     ret
  463. ptake1:    mov di,takadr
  464.     add di,size takinfo
  465.     push di
  466.     mov ah,cmtxt
  467.     lea bx,[di].takbuf        ; convenient place to parse name into
  468.     mov dx,offset filmsg        ; Help in case user types "?".
  469.     call comnd
  470.      pop di
  471.      ret
  472.      nop
  473.     pop di                ; restore frame address
  474.     cmp ah,0
  475.     je ptake2            ; empty, complain.
  476.     push di                ; keep it on stack.
  477.     lea si,[di].takbuf        ; get buffer back
  478.     mov bl,ah            ; length of thing parsed
  479.     mov bh,0
  480.     mov byte ptr [bx+si],0        ; make it asciz
  481.     mov ax,si            ; point to name again
  482.     call spath            ; is it around?
  483.     pop di                ; need this back
  484.     jc ptake2            ; no, go complain
  485.     mov dx,ax            ; point to name from spath
  486.     mov ah,open2            ; 2.0 open call
  487.     mov al,0            ; open for reading
  488.     int dos
  489.     jnc ptake3            ; open ok, keep going
  490. ptake2:    mov ah,prstr
  491.     mov dx,offset erms31
  492.     int dos
  493.     ret
  494. ptake3:    inc taklev
  495.     mov takadr,di
  496.     mov word ptr [di].takfcb+1,ax    ; save file descriptor
  497.     mov byte ptr [di].takfcb,0feh    ; mark as 2.0 file descriptor
  498.     mov bx,ax            ; need descriptor here
  499.     mov ah,lseek
  500.     mov al,2
  501.     mov cx,0
  502.     mov dx,cx            ; seek 0 bytes from end
  503.     int dos
  504.     mov [di].takcnt,ax
  505.     mov [di].takcnt+2,dx        ; store length
  506.     mov ah,lseek
  507.     mov al,0
  508.     mov cx,0
  509.     mov dx,cx            ; now seek back to beginning
  510.     int dos
  511.     cmp flags.takflg,0
  512.     je ptake4
  513.     mov ah,prstr
  514.     mov dx,offset crlf
  515.     int dos
  516. ptake4:    call takrd        ; Get a buffer full of data.
  517.     jmp rskp
  518. PTAKE    ENDP
  519.  
  520.  
  521. ;     TAKE commands from a file.  [25t]
  522.  
  523. TAKE    PROC    NEAR
  524.     cmp dosnum,0
  525.     je take1
  526.     jmp ptake            ; use this for 2.0
  527. take1:    cmp taklev,maxtak        ; Hit our limit?
  528.     jl take2                ; Continue if still OK.
  529.     mov ah,prstr
  530.     mov dx,offset erms30        ; Complain.
  531.     int dos 
  532.     ret
  533. take2:    mov bx,takadr
  534.     add bx,size takinfo
  535.     push bx
  536.     lea dx,[bx].takfcb
  537.      mov comand.cmcr,0        ; Filename must be specified.
  538.     mov ah,cmifi
  539.     mov bx,offset filhlp1
  540.     call comnd
  541.      pop bx
  542.      ret                ; Make sure this is three bytes long.
  543.      nop
  544.     pop bx
  545.     mov byte ptr [bx].takfcb+32,0    ; have to clear current record in fcb
  546.     mov ah,openf
  547.     lea dx,[bx].takfcb
  548.     int dos
  549.     cmp al,0FFH            ; File not found?
  550.     jne take3
  551.     mov ah,prstr
  552.     mov dx,offset erms31
  553.     int dos
  554. take3:    inc taklev
  555.     mov takadr,bx
  556.     mov ax,word ptr [bx+16].takfcb
  557.     mov [bx].takcnt,ax
  558.     mov ax,word ptr [bx+18].takfcb
  559.     mov [bx].takcnt+2,ax        ; copy size into takinfo
  560.     cmp flags.takflg,0
  561.     je take4
  562.     mov ah,prstr
  563.     mov dx,offset crlf
  564.     int dos
  565. take4:    call takrd            ; Get a buffer full of data.
  566.     jmp rskp
  567. TAKE     ENDP
  568.  
  569. TAKRD    PROC    NEAR
  570.     push bx
  571.     push cx    
  572.     push dx
  573.     mov bx,takadr
  574.     cmp byte ptr [bx].takfcb,0feh    ; is it a 2.0 file handle?
  575.     jne takrd1            ; no, handle differently
  576.     push bx                ; save frame address
  577.     lea dx,[bx].takbuf        ; buffer to read into
  578.     mov cx,dmasiz            ; # of bytes to read
  579.     mov ah,readf2            ; 2.0 read call
  580.     mov bx,word ptr [bx].takfcb+1    ; file handle is stored here
  581.     int dos
  582.     pop bx                ; restore frame address
  583.     jmp takrd2            ; rejoin common exit
  584.  
  585. takrd1:    mov ah,setdma
  586.     lea dx,[bx].takbuf
  587.     int dos
  588.     mov ah,readf
  589.     lea dx,[bx].takfcb
  590.     int dos
  591.     mov ah,setdma
  592.     lea dx,buff
  593.     int dos
  594. takrd2:    mov [bx].takchl,dmasiz
  595.     lea ax,[bx].takbuf
  596.     mov [bx].takptr,ax
  597.     pop dx
  598.     pop cx
  599.     pop bx
  600.     ret
  601.  
  602. TAKRD    ENDP
  603.  
  604. ; copy the path into pthbuf
  605. ; enter with ax/ environment segment address
  606. ; works in 2.0 only.
  607. getpath    proc    near
  608.     push    es
  609.     mov    bx,ds
  610.     mov    es,bx            ; address data segment
  611.     mov    bx,offset pthnam    ; thing to find
  612.     mov    cx,pthlen        ; length of it
  613.     mov    dx,offset pthbuf    ; place to put it
  614.     mov    byte ptr pthbuf,0    ; initialize to null...
  615.     call    getenv            ; get environment value
  616.     pop    es
  617.     ret                ; and return
  618. getpath    endp
  619.  
  620. ; copy the comspec into cmspbuf
  621. ; enter with ax/ environment segment address
  622. ; works in 2.0 only.
  623. getcsp    proc    near
  624.     push    es
  625.     mov    bx,ds
  626.     mov    es,bx            ; address data segment
  627.     mov    bx,offset cmspnam    ; thing to find
  628.     mov    cx,cmsplen        ; length of it
  629.     mov    dx,offset cmspbuf    ; place to put it
  630.     call    getenv            ; get environment value
  631.     pop    es
  632.     ret                ; and return
  633. getcsp    endp
  634.  
  635. ; find a path variable.  Enter with ax/ environment segment,
  636. ; bx/ variable to find (incl =), cx/ length of variable name,
  637. ; dx/ address to store value at.
  638. ; The buffer given in dx is unchanged if the variable isn't found
  639. getenv    proc    near
  640.     push    ds
  641.     push    es
  642.     mov    es,ax            ; address segment
  643.     mov    di,0            ; offset in segment
  644. geten1:    cmp    es:byte ptr [di],0    ; end?
  645.     je    geten4            ; yes, forget it
  646.     push    cx            ; save counter
  647.     push    di            ; and offset
  648.     mov    si,bx
  649.     repe    cmpsb            ; is it the one?
  650.     pop    di
  651.     pop    cx            ; restore these
  652.     je    geten2            ; found it, break loop
  653.     push    cx            ; preserve again
  654.     mov    cx,0ffffh        ; bogus length
  655.     mov    al,0            ; marker to look for
  656.     repne    scasb            ; search for it
  657.     pop    cx            ; restore length
  658.     jmp    geten1            ; loop thru rest of environment
  659. geten2:    add    di,cx            ; skip to definition
  660.     mov    si,di            ; this is source
  661.     mov    di,dx            ; destination as given
  662.     mov    ax,ds
  663.     mov    bx,es
  664.     mov    ds,bx
  665.     mov    es,ax            ; exchange segment regs for copy
  666. geten3:    lodsb                ; get a byte
  667.     stosb                ; drop it off
  668.     cmp    al,0            ; end of string
  669.     jne    geten3            ; no, go on
  670. geten4:    pop    es
  671.     pop    ds            ; restore registers
  672.     ret                ; and return
  673. getenv    endp
  674.  
  675. ; put kermit.ini onto take stack if it exists.  Just like
  676. ; the take command, except it doesn't read a filename.
  677.  
  678. rdinit    proc    near        ; read kermit init file...
  679.     mov al,dosnum        ; get dos version
  680.     or al,al
  681.     jne rdini4        ; post 2.0, use file handle instead...
  682.     mov bx,takadr
  683.     add bx,size takinfo    ; bump take ptr, point to current take frame
  684.     lea di,[bx].takfcb    ; destination is fcb
  685.     mov ax,ds
  686.     mov es,ax        ; destination segment = source segment
  687.     mov si,offset ininam    ; name of init file
  688.     mov cx,12        ; 8 char name + 3 char ext + 1 char drive...
  689.     rep movsb        ; copy it in
  690.     mov byte ptr [bx].takfcb+32,0 ; have to clear current record in fcb
  691.     mov ah,openf
  692.     lea dx,[bx].takfcb
  693.     int dos
  694.     cmp al,0FFH        ; File not found?
  695.     jne rdini1        ; no, keep going
  696.     ret            ; else just return, no init file
  697. rdini1:    inc taklev        ; bump take level
  698.     mov takadr,bx        ; save current take frame ptr
  699.     mov ax,word ptr [bx+16].takfcb
  700.     mov [bx].takcnt,ax
  701.     mov ax,word ptr [bx+18].takfcb
  702.     mov [bx].takcnt+2,ax    ; copy size into takinfo
  703. rdini2:    cmp flags.takflg,0
  704.     je rdini3
  705.     mov ah,prstr
  706.     mov dx,offset crlf
  707.     int dos
  708. rdini3:    call takrd        ; Get a buffer full of data.
  709.     ret
  710.  
  711. rdini4:    mov ax,offset ininm2    ; name to try
  712.     push bx
  713.     call spath        ; can we find it?
  714.     pop di
  715.     jc rdini6        ; no, forget it, go use it
  716.     mov dx,ax        ; point to name
  717.     mov ah,open2        ; 2.0 open function
  718.     mov al,0        ; for reading...
  719.     int dos
  720.     jc rdini6        ; can't open, forget it
  721.  
  722. rdini5:    inc taklev        ; bump take level
  723.     add takadr,size takinfo
  724.     mov di,takadr        ; get current frame ptr
  725.     mov word ptr [di].takfcb+1,ax    ; save file handle
  726.     mov byte ptr [di].takfcb,0feh    ; mark as a handle
  727.     mov bx,ax            ; move file ptr
  728.     mov ah,lseek
  729.     mov al,2
  730.     mov cx,0
  731.     mov dx,0            ; seek to end of file
  732.     int dos
  733.     mov [di].takcnt,ax        ; copy file size
  734.     mov [di].takcnt+2,dx        ; into structure
  735.     mov al,0
  736.     mov ah,lseek
  737.     mov cx,0
  738.     mov dx,0
  739.     int dos                ; seek back to beginning
  740.     jmp rdini2            ; go rejoin common exit
  741. rdini6:    ret                ; no init file, just return
  742. rdinit    endp
  743.  
  744. ; get command line into a macro buffer.
  745.  
  746. gcmdlin    proc    near
  747.     push    ds
  748.     push    es
  749.     cld
  750.     mov    es,psp            ; address psp
  751.     mov    ch,0
  752.     mov    cl,es:[cline]        ; length of cmd line
  753.     mov    di,cline+1        ; point to actual line
  754.     mov    al,' '
  755.     jcxz    gcmdl3            ; no command line, forget it.
  756.     repe    scasb            ; skip over spaces
  757.     je    gcmdl3            ; all spaces, forget it
  758.     mov    si,di            ; this is first non-space
  759.     dec    si            ; pre-incremented...
  760.     inc    cx
  761.     inc    taklev            ; bump take level
  762.     add    takadr,size takinfo    ; address new take frame
  763.     mov    bx,takadr
  764.     mov    byte ptr [bx].takfcb,0ffh ; mark as a macro
  765.     push    cx            ; save length
  766.     push    ds            ; and segment
  767.     lea    di,[bx].takbuf        ; into take buffer
  768.     mov    ax,ds
  769.     mov    ds,psp
  770.     mov    es,ax            ; switch segments for copy
  771. gcmdl1:    lodsb                ; get a byte
  772.     cmp    al,','            ; comma?
  773.     jne    gcmdl2            ; no, keep going
  774.     mov    al,cr            ; convert to cr
  775. gcmdl2:    stosb                ; deposit it
  776.     loop    gcmdl1            ; copy whole cmd
  777.     pop    ds            ; restore segment
  778.     mov    si,offset eexit        ; something to tack onto end
  779.     mov    cx,leexit        ; length of it
  780.     rep    movsb            ; copy it in
  781.     pop    cx            ; restore len
  782.     add    cx,leexit        ; count wnat we added
  783.     
  784.     lea    ax,[bx].takbuf
  785.     mov    [bx].takptr,ax        ; init buffer ptr
  786.     mov    [bx].takchl,cl        ; chars remaining
  787.     mov    [bx].takcnt,cx        ; and all chars
  788.     mov    [bx].takcnt+2,0        ; clear high order
  789. gcmdl3:    pop    es
  790.     pop    ds
  791.     ret
  792. gcmdlin    endp
  793.  
  794. ;    This routine prints the prompt and specifies the reparse address.
  795.  
  796. PROMPT    PROC  NEAR
  797.     mov comand.cmprmp,dx    ; save the prompt
  798.     pop bx            ; Get the return address.
  799.     mov comand.cmrprs,bx    ; Save as addr to go to on reparse.
  800.     mov comand.cmostp,sp    ; Save for later restoral.
  801.     push bx            ; Put it on the stack again.
  802.     mov bx,offset comand.cmdbuf
  803.     mov comand.cmcptr,bx    ; Initialize the command pointer.
  804.     mov comand.cmdptr,bx
  805.     mov ah,0
  806.     mov comand.cmaflg,ah    ; Zero the flags.
  807.     mov comand.cmccnt,ah
  808.     mov comand.cmsflg,0FFH
  809.     cmp flags.takflg,0    ; look at take flag
  810.     jne promp1        ; supposed to echo, skip this check...
  811.     cmp taklev,0        ; inside a take file?
  812.     je promp1        ; no, keep going
  813.     ret            ; yes, return
  814. promp1:    mov ah,prstr
  815.     mov dx,offset crlf
  816.     int dos
  817.     mov ah,prstr        ; Print the prompt.
  818.     mov dx,comand.cmprmp
  819.     int dos
  820.     ret
  821. PROMPT    ENDP
  822.  
  823. ; Erase specified file(s).
  824. DELETE    PROC    NEAR
  825.      mov comand.cmcr,0    ; Filename must be specified.
  826.     mov ah,cmifi        ; Parse an input filespec.
  827.     mov dx,offset fcb
  828.     mov bx,offset filhlp2    ; Text of help message.
  829.     call comnd
  830.      jmp r            ; Bad filename.
  831.     mov ah,cmcfm        ; Parse a confirm.
  832.     call comnd
  833.      jmp r
  834.     cld
  835.     mov di,offset fcb+1
  836.     mov al,'?'
  837.     mov cx,11        ; # of chars in a name
  838.     repe scasb        ; are they all ?'s?
  839.     jne del1        ; no, skip message
  840.     mov dx,offset infms1
  841.     call prompt
  842.     mov ah,cmkey
  843.     mov dx,offset yestab
  844.     mov bx,0
  845.     call comnd
  846.      jmp r
  847.     push bx
  848.     mov ah,cmcfm
  849.     call comnd
  850.      pop bx
  851.      ret
  852.      nop
  853.     pop bx
  854.     cmp bx,0
  855.     jne del1
  856.     jmp rskp
  857. del1:    mov dx,offset fcb
  858.     mov ah,sfirst        ; See if any files match this specification.
  859.     int dos    
  860.     cmp al,0FFH        ; No matches?
  861.     jne del2
  862.     mov ah,prstr
  863.     mov dx,offset erms32
  864.     int dos
  865.     jmp rskp
  866. del2:    mov dx,offset fcb
  867.     mov ah,delf        ; Erase the file(s).
  868.     int dos
  869.     mov dx,offset infms8
  870.     mov ah,prstr        ; Say we did so.
  871.     int dos
  872.     jmp rskp
  873. DELETE    ENDP    
  874.  
  875. CHKDSK    PROC    NEAR
  876.     mov ah,cmcfm
  877.     call comnd
  878.      jmp r
  879.     cmp dosnum,0
  880.     je chkds1            ; yes, have to do it the hard way
  881.     mov si,offset chkdcmd        ; point to cmd
  882.     mov cx,chkdlen            ; and length
  883.     jmp crun            ; and go execute it nicely
  884. chkds1:    push es
  885.     mov ax,ds
  886.     mov es,ax
  887.     mov di,offset fcb
  888.     mov si,offset chkfil
  889.     mov cx,chkflen
  890.     rep movsb
  891.     mov dx,offset msfinal + 15 ; End of pgm plus roundoff.
  892.     mov cl,4
  893.     shr dx,cl            ; Divide to get segment.
  894.     add dx,seg datas        ; Get past the stack.
  895.     mov es,dx            ; remember where segment is.
  896.     mov ah,makseg            ; Create new PSP.
  897.     int dos
  898.     mov ax,siz            ; Update machine size.
  899.     mov es:2,ax
  900.     mov es: byte ptr [deffcb],0    ; Blank default fcb.
  901.     mov di,deffcb+1
  902.     mov al,' '            ; Blank out fcb.
  903.     mov cx,fcbsiz
  904.     rep stosb
  905.     mov word ptr es:[terma],offset term    ; Termination address.
  906.     mov es:[terma+2],cs
  907.     mov ah,openf
  908.     mov dx,offset fcb
  909.     int dos
  910.     inc al
  911.     jnz chkok
  912.     mov dx,offset erms33
  913.     mov ah,prstr
  914.     int dos
  915.     jmp chkend
  916.  
  917. chkok:    mov byte ptr fcb+32,0        ; set current record field
  918.     mov di,100h            ; offset to copy into
  919. lp:    mov dx,offset fcb
  920.     mov ah,readf
  921.     int dos
  922.     push ax                ; save status
  923.     mov si,offset buff
  924.     mov cx,dmasiz/2            ; Word size of DMA
  925.     rep movsw            ; copy into new segment...
  926.     pop ax
  927.     cmp al,1            ; End of file
  928.     je dun
  929.     cmp al,3            ; Done here too
  930.     jne lp
  931. dun:    mov ssave,sp            ; Save stack pointer.
  932.     mov ax,es
  933.     mov word ptr cs:[doit+2],ax     ; Set segment for CHKDSK.
  934.     mov ds,ax
  935.     mov ss,ax
  936.     mov ax,0
  937.     jmp cs: dword ptr [doit]    ; Call CHKDSK.
  938. term:    mov ax,seg datas        ; Reset data area.
  939.     mov ds,ax
  940.     mov sp,ssave
  941.     mov ax,seg stack
  942.     mov ss,ax
  943.     mov ah,setdma
  944.     mov dx,offset buff
  945.     int dos                ; restore dma address!!
  946. chkend:    pop es
  947.     jmp rskp
  948. doit    dd 100h
  949. CHKDSK    ENDP
  950.  
  951. ; Get directory listing.
  952. DIRECT    PROC    NEAR
  953.     mov ah,dosver        ; See what level of DOS we're at.
  954.     int dos
  955.     cmp al,0        ; Level 2.0 or above?
  956.     jne dir4        ; Yes - get directory the easy way.
  957.     mov comand.cmcr,1    ; Allow plain CR (so DIR == DIR *.*).
  958.     mov ah,cmifi        ; Get input file spec.
  959.     mov dx,offset fcb    ; Give the address for the FCB.
  960.     mov bx,offset filhlp3
  961.     call comnd
  962.      jmp r
  963.     mov ah,cmcfm        ; Parse a confirm.
  964.     call comnd
  965.      jmp r
  966.     mov comand.cmcr,0    ; Reset this. 
  967.     push es
  968.     mov ax,ds
  969.     mov es,ax
  970.     mov temp1,0FFH
  971.     mov di,offset nambuf
  972. dir0:    call getfn        ; Get a matching file name.
  973.     cmp al,0FFH        ; Retcode -- are we done?
  974.     je dir1            ; Yes, just leave.
  975.     call dumpit        ; Print it or dump to buffer.
  976.     jmp dir0
  977. dir1:    pop es
  978.     jmp rskp
  979.  
  980. dir4:    mov si,offset cmspbuf    ; command processor
  981.     mov di,offset dirnam
  982. dir5:    lodsb            ; get a byte
  983.     or al,al
  984.     jz dir6            ; stop on the null
  985.     stosb            ; otherwise copy it in
  986.     jmp dir5        ; and keep going
  987. dir6:    mov si,offset dircmd    ; add directory command to it
  988.     mov cx,dirclen
  989.     rep movsb
  990.     mov ah,cmtxt        ; parse with cmtxt so we can have paths...
  991.     mov bx,di        ; next available byte
  992.     mov dx,offset filwmsg    ; In case user wants help. 
  993.     call comnd
  994.      jmp r
  995.     mov cl,ah
  996.     mov ch,0        ; length of name
  997.     sub di,offset dirnam    ; compute # of bytes used
  998.     add cx,di
  999.     mov si,offset dirnam    ; dir cmd
  1000.     jmp crun        ; join run cmd from there.
  1001. DIRECT    ENDP
  1002.  
  1003. ; the version command - print our version number
  1004. prvers    proc    near
  1005.     mov    ah,cmcfm
  1006.     call    comnd
  1007.      jmp    r
  1008.     mov    ah,prstr
  1009.     mov    dx,offset crlf
  1010.     int    dos
  1011.     mov    ah,prstr
  1012.     mov    dx,offset machnam    ; print machine name
  1013.     int    dos
  1014.     mov    ah,prstr            ; Print the version header.
  1015.     mov    dx,offset versio
  1016.     int    dos
  1017.     jmp    rskp
  1018. prvers    endp
  1019.  
  1020. ; the type command - type out a file
  1021. typec    proc    near
  1022.     mov si,offset cmspbuf    ; command processor
  1023.     mov di,offset dirnam    ; nice destination buffer
  1024. type1:    lodsb            ; get a byte
  1025.     or al,al
  1026.     jz type2        ; stop on the null
  1027.     stosb            ; otherwise copy it in
  1028.     jmp type1        ; and keep going
  1029. type2:    mov al,' '
  1030.     stosb
  1031.     mov al,dirswt        ; get switch char
  1032.     stosb            ; put in buffer
  1033.     mov si,offset typcmd    ; add type command
  1034.     mov cx,typclen
  1035.     rep movsb
  1036.     mov ah,cmtxt        ; parse with cmtxt so we can have paths...
  1037.     mov bx,di        ; next available byte
  1038.     mov dx,offset filmsg    ; In case user wants help. 
  1039.     call comnd
  1040.      jmp r
  1041.     mov cl,ah
  1042.     mov ch,0        ; length of name
  1043.     sub di,offset dirnam    ; compute # of bytes used
  1044.     add cx,di
  1045.     mov si,offset dirnam    ; dir cmd
  1046.     jmp crun        ; join run cmd from there.
  1047. typec    endp
  1048.  
  1049. getfn:    cmp temp1,0FFH
  1050.     jne gtfn1
  1051.     mov ah,sfirst        ; Any matches?
  1052.     mov dx,offset fcb
  1053.     int dos
  1054.     cmp al,0FFH        ; Means no matches.
  1055.     je gtfn5
  1056.     call savfcb
  1057.     mov temp1,0
  1058.     jmp gtfn4
  1059. gtfn1:    cmp flags.wldflg,0FFH    ; Wilcard seen?
  1060.     je gtfn2        ; Yes, get next file.
  1061.     mov al,0FFH        ; No, set retcode.
  1062.     ret
  1063. gtfn2:    call rstfcb
  1064.     mov ah,snext
  1065.     mov dx,offset fcb
  1066.     int dos
  1067.     cmp al,0        ; Any more matches?
  1068.     je gtfn3        ; Yes keep going.
  1069.     mov al,0FFH        ; OK return code.
  1070.     ret
  1071. gtfn3:    call savfcb
  1072. gtfn4:    push di
  1073.     mov si,offset buff    ; Data is here.
  1074.     mov di,offset fcb    ; Copy to here.
  1075.     mov cx,37
  1076.     repne movsb
  1077.     pop di
  1078.     call nicnam        ; Make name nice for printing.
  1079.     mov al,0
  1080.     ret
  1081. gtfn5:    mov ah,prstr        ; Don't print if a server. 
  1082.     mov dx,offset erms32    ; Say no matches.
  1083.     int dos
  1084.     mov al,0FFH        ; Failure return code.
  1085.     ret
  1086.  
  1087. savfcb:    push di
  1088.     mov si,offset fcb    ; Data is here.
  1089.     mov di,offset cpfcb    ; Copy to here.
  1090.     mov cx,37
  1091.     repne movsb
  1092.     pop di
  1093.     ret
  1094.  
  1095. rstfcb:    push di
  1096.     mov si,offset cpfcb    ; Data is here.
  1097.     mov di,offset fcb    ; Copy to here.
  1098.     mov cx,37
  1099.     repne movsb
  1100.     pop di    
  1101.     ret
  1102.  
  1103. nicnam:    mov al,CR        ; Add CRLF before print names
  1104.     stosb
  1105.     mov al,LF
  1106.     stosb
  1107.     mov cx,8
  1108.     mov si,offset fcb+1
  1109.     repne movsb        ; Get the file name.
  1110.     mov al,' '
  1111.     stosb
  1112.     mov cx,3
  1113.     repne movsb
  1114.     mov al,tab
  1115.     stosb
  1116.     mov al,' '
  1117.     stosb
  1118.     mov ah,openf
  1119.     mov dx,offset fcb
  1120.     int dos    
  1121.     mov bx,offset fcb+18    ; Get hi order word of file size.
  1122.     mov ax,[bx]
  1123.     mov dx,ax
  1124.     mov bx,offset fcb+16    ; Get lo order word.
  1125.     mov ax,[bx]
  1126.     call nout2x        ; Get it in decimal. 
  1127.     mov al,tab
  1128.     stosb
  1129.     mov al,' '
  1130.     stosb
  1131.     mov ah,0
  1132.     mov si,offset fcb+20
  1133.     lodsb
  1134.     mov fildat+1,al
  1135.     lodsb
  1136.     mov fildat,al        ; Date field of fcb.
  1137.     mov cl,5
  1138.     shr fildat+1,cl
  1139.     and fildat,1
  1140.     mov cl,3
  1141.     shl fildat,cl
  1142.     mov al,fildat
  1143.     or al,fildat+1        ; Get the month field.
  1144.     cmp al,9
  1145.     jg nic0
  1146.     push ax
  1147.     mov al,' '
  1148.     stosb
  1149.     pop ax
  1150. nic0:    call nout2        ; Make it decimal.
  1151.     mov al,'-'
  1152.     stosb
  1153.     mov si,offset fcb+20    ; Get date field.
  1154.     lodsb
  1155.     and al,1FH
  1156.     cmp al,10        ; Only one digit?
  1157.     jge nic0x
  1158.     push ax
  1159.     mov al,'0'        ; Make it two digits.
  1160.     stosb
  1161.     pop ax
  1162. nic0x:    call nout2        ; Make it decimal.
  1163.     mov al,'-'
  1164.     stosb
  1165.     mov si,offset fcb+21    ; Get the year field.
  1166.     lodsb
  1167.     shr al,1
  1168.     add al,80
  1169.     cmp al,100        ; At the year 2000 or above?
  1170.     js nic0y        ; No, just go on.
  1171.     sub al,100        ; Go back to two digits.
  1172. nic0y:    cmp al,10        ; Only one digit?
  1173.     jge nic0z
  1174.     push ax
  1175.     mov al,'0'        ; Make it two digits.
  1176.     stosb
  1177.     pop ax
  1178. nic0z:    call nout2        ; Make it decimal.
  1179.     mov al,tab
  1180.     stosb
  1181.     mov si,offset fcb+23    ; Get time field of fcb.
  1182.     lodsb
  1183.     mov cl,3        ; Get the hour field.
  1184.     shr al,cl
  1185.     mov tmp,'a'        ; For AM.
  1186.     cmp al,12        ; Before noon?
  1187.     jl nic1
  1188.     mov tmp,'p'        ; It's PM.
  1189.     je nic1            ; Don't change "12" to "0".
  1190.     sub al,12        ; Use a 12 hr. clock.
  1191. nic1:    cmp al,0        ; Just after midnight?
  1192.     jne nic1x
  1193.     add al,12        ; Make it "12" instead of "0".
  1194. nic1x:    cmp al,10        ; Pad with a space?
  1195.     jge nic2
  1196.     push ax
  1197.     mov al,' '
  1198.     stosb
  1199.     pop ax
  1200. nic2:    call nout2        ; Make it decimal.
  1201.     mov al,':'        ; Separate hours and minutes.
  1202.     stosb
  1203.     mov si,offset fcb+23    ; Get the minutes field.
  1204.     lodsb
  1205.     and al,07
  1206.     mov cl,3
  1207.     shl al,cl
  1208.     mov ah,al
  1209.     mov si,offset fcb+22
  1210.     lodsb
  1211.     mov cl,5
  1212.     shr al,cl
  1213.     or al,ah
  1214.     mov ah,0
  1215.     cmp al,10        ; Would there be a leading zero.
  1216.     jge nic3
  1217.     push ax
  1218.     mov al,'0'
  1219.     stosb
  1220.     pop ax
  1221. nic3:    call nout2        ; Make it decimal.
  1222.     mov al,tmp        ; Add 'a' (AM) or 'p' (PM).
  1223.     stosb
  1224.     mov ah,closf
  1225.     mov dx,offset fcb
  1226.     int dos
  1227.     ret
  1228.  
  1229. ; For now, just print it.
  1230. dumpit:    mov al,'$'
  1231.     stosb
  1232.     mov ah,prstr
  1233.     mov dx,offset nambuf
  1234.     int dos
  1235.     mov di,offset nambuf
  1236.     ret
  1237.  
  1238. ; push to an inferior command parser
  1239. ; entry fpush (fast push...) pushes without waiting for a confirm.
  1240. ; returns rskp.
  1241. dopush    proc    near
  1242.     cmp    dosnum,0        ; < 2.0 ?
  1243.     jne    dopus1            ; no, go on
  1244.     mov    dx,offset erms34
  1245.     mov    ah,prstr
  1246.     int    dos
  1247.     jmp    rskp
  1248. dopus1:    mov    ah,cmcfm
  1249.     call    comnd
  1250.      jmp    r
  1251. fpush:    mov    si,offset cmspbuf    ; name of parser
  1252.     push    si            ; save beginning
  1253.     sub    cx,cx            ; initial length
  1254. dopus2:    lodsb
  1255.     inc    cx            ; count this
  1256.     or    al,al            ; at end?
  1257.     jnz    dopus2            ; no, keep going
  1258.     pop    si            ; restore cmd
  1259.     dec    cx            ; this is incremented one over
  1260.     jmp    short crun        ; go run it
  1261. dopush    endp
  1262.  
  1263. ; crun - run an arbitrary program.  Enter with si/address of whole
  1264. ; cmd, cx/length of cmd.
  1265. CRUN    proc    near
  1266.     push cx            ; save length of cmd
  1267.     mov ax,ds
  1268.     mov es,ax        ; address dest segment
  1269.     mov di,offset nambuf
  1270.     rep movsb        ; copy command so we can mess with it
  1271.     pop cx
  1272.     mov si,offset nambuf    ; point to command
  1273.     jmp short run3        ; and join run code
  1274. CRUN    ENDP
  1275.  
  1276. RUN    PROC    NEAR
  1277.     cmp dosnum,0
  1278.     jne run1
  1279.     mov ah,prstr
  1280.     mov dx,offset erms34    ; Complain.
  1281.     int dos
  1282.     jmp rskp
  1283. run1:    mov ah,cmtxt        ; Get program name.
  1284.     mov bx,offset nambuf    ; Convenient buffer.
  1285.     mov dx,offset filmsg    ; In case user wants help.
  1286.     call comnd
  1287.      nop
  1288.      nop
  1289.      nop
  1290.     cmp ah,0
  1291.     jne run2
  1292.     mov ah,prstr
  1293.     mov dx,offset erms35
  1294.     int dos
  1295.     jmp rskp
  1296. run2:    mov cl,ah
  1297.     mov ch,0
  1298.     mov si,offset nambuf
  1299.  
  1300. ; alternate entry if cmd is already known.  Source cmd ptr in si
  1301. ; is trashed.
  1302. run3:    push cx
  1303.     push si                ; preserve pointers
  1304.     call tstbat            ; is it a batch file?
  1305.     jnc run3a            ; no, keep going
  1306.     mov dx,0
  1307.     mov si,offset cmspbuf
  1308.     mov di,offset batbuf
  1309. run3b:    lodsb
  1310.     or al,al
  1311.     jz run3c
  1312.     inc dl
  1313.     stosb
  1314.     jmp run3b
  1315. run3c:    mov si,offset slashc
  1316.     mov cx,slslen
  1317.     add dx,cx
  1318.     rep movsb            ; copy the "/c" stuff
  1319.     pop si
  1320.     pop cx                ; restore command from stack
  1321.     add dx,cx            ; keep running length
  1322.     rep movsb
  1323.     mov si,offset batbuf
  1324.     mov cx,dx            ; put length where crun expects it
  1325.     jmp crun            ; and go run it with cmd processor
  1326.  
  1327. ; not a bat file, just exec it.
  1328. run3a:    mov ah,prstr
  1329.     mov dx,offset crlf
  1330.     int dos
  1331.     pop si
  1332.     pop cx
  1333.     mov bx,cx
  1334.     mov byte ptr [si+bx],cr    ; end string with a cr for dos.
  1335.     mov di,offset cmdnam
  1336.     mov ax,ds
  1337.     mov es,ax
  1338. run4:    lodsb
  1339.     cmp al,' '
  1340.     jne run5
  1341.     dec si            ; back up over space
  1342.     jmp short run6        ; and exit loop
  1343. run5:    stosb
  1344.     loop run4
  1345. run6:    mov byte ptr [di],0    ; terminate string
  1346.     dec si            ; point back a byte into argument
  1347.     mov [si],cl        ; put length of argument here
  1348.     mov exearg+2,si        ; pointer to argument string
  1349.     mov exearg+4,ds        ; segment of same
  1350.     inc si            ; pass length over
  1351.     mov al,1        ; scan leading separators
  1352.     mov di,offset exefcb    ; parse into this fcb
  1353.     mov ah,prsfcb
  1354.     int dos            ; go parse the fcb
  1355.     mov al,1        ; scan leading separators
  1356.     mov di,offset exefcb2    ; second fcb to fill
  1357.     mov ah,prsfcb
  1358.     int dos            ; parse the fcb
  1359.     mov es,psp        ; point to psp again
  1360.     mov ax,es:[env]        ; get environment ptr
  1361.     mov exearg,ax        ; put into argument block
  1362. ;    mov bx,offset msfinal + 15 ; end of pgm + roundup
  1363. ;    mov cl,4
  1364. ;    shr bx,cl        ; compute # of paragraphs in last segment
  1365. ;    mov ax,seg datas    ; end of kermit
  1366. ;    sub ax,psp        ; minus beginning...
  1367. ;    add bx,ax        ; # of paragraphs occupied
  1368. ;    mov ah,setblk
  1369. ;    int dos
  1370. ;    jc run7            ; nope...
  1371.     mov ax,ds
  1372.     mov es,ax        ; put es segment back
  1373.     mov ax,offset cmdnam    ; point to cmd name again
  1374.     call spath        ; look for it
  1375.     jc run8            ; not found, go complain
  1376.     mov dx,ax        ; point to command name
  1377.     mov al,0        ; load and execute...
  1378.     mov ah,exec
  1379.     mov bx,offset exearg    ; and to arguments
  1380.     mov ssave,sp        ; save stack ptr
  1381.     int dos            ; go run the program
  1382.     mov ax,seg datas
  1383.     mov ds,ax        ; reset data segment
  1384.     mov ax,seg stack
  1385.     mov ss,ax        ; and stack segment
  1386.     mov sp,ssave        ; restore stack ptr
  1387.     mov ah,setdma
  1388.     mov dx,offset buff
  1389.     pushf            ; save flags
  1390.     int dos            ; restore dma address!!
  1391.     popf            ; recover flags
  1392.     jc run8            ; error, handle.
  1393.     jmp rskp        ; ok, return
  1394. run7:    mov ah,prstr
  1395.     mov dx,offset erms36
  1396.     int dos
  1397.     jmp rskp
  1398. run8:    mov ah,prstr
  1399.     mov dx,offset erms37
  1400.     int dos
  1401.     jmp rskp
  1402. RUN    ENDP
  1403.  
  1404. ; enter with si/ command name, cx/ length.  Returns with carry on if
  1405. ; this is a .bat file...  Preserves all registers but bp.
  1406. tstbat    proc    near
  1407.     saveac    <si,di,cx,ax>
  1408.     mov    al,'.'
  1409.     mov    di,si
  1410.     repne    scasb            ; hunt for the dot first
  1411.     jne    tstba2            ; not around, just fail
  1412.     mov    si,di
  1413.     mov    di,offset batnam
  1414.     mov    cx,3            ; length of bat name
  1415. tstba1:    lodsb                ; get a byte from the command
  1416.     and    al,not 20h        ; uppercase
  1417.     cmp    al,[di]            ; is it right?
  1418.     jne    tstba2            ; no, fail
  1419.     inc    di
  1420.     loop    tstba1            ; loop thru whole name
  1421.     stc                ; is a bat file, carry on.
  1422.     ret
  1423. tstba2:    clc                ; fail...
  1424.     ret
  1425. tstbat    endp
  1426.  
  1427. ; the show command
  1428. showcmd    proc    near
  1429.     mov    ah,cmkey
  1430.     mov    dx,offset shotab
  1431.     xor    bx,bx            ; no canned help
  1432.     call    comnd
  1433.      jmp    r
  1434.     call    bx            ; call the handler
  1435.      jmp    r
  1436.     jmp    rskp            ; and return
  1437. showcmd    endp
  1438.  
  1439. intbrk:    cmp flags.debug,1    ; Debug mode?
  1440.     je intb1        ; Yes, then don't ignore the ¬C.
  1441.     push ax
  1442.     push ds
  1443.     mov ax,seg datas
  1444.     mov ds,ax
  1445.     mov flags.cxzflg,'C'    ; Say we saw a ¬C.
  1446.     mov pack.state,'A'    ; Set the state to abort.
  1447.     pop ds
  1448.     pop ax
  1449.     iret
  1450. intb1:    jmp in3ad        ; Original break interrupt address.
  1451.  
  1452. NOUT2     PROC    NEAR
  1453.     push ax
  1454.     push dx
  1455.     mov temp,10        ; Divide quotient by 10.
  1456.     cwd            ; Convert word to doubleword.
  1457.     div temp        ; AX <-- Quo, DX <-- Rem.
  1458.     cmp ax,0        ; Are we done?    
  1459.     jz nout0        ; Yes.
  1460.     call nout2        ; If not, then recurse.
  1461. nout0:    add dl,'0'        ; Make it printable.
  1462.     mov temp,ax
  1463.     mov al,dl
  1464.     stosb
  1465.     mov ax,temp
  1466.     pop dx
  1467.     pop ax
  1468.     ret            ; We're done. [21c]
  1469. NOUT2    ENDP
  1470.  
  1471. NOUT2X     PROC    NEAR
  1472.     push ax
  1473.     push dx
  1474.     push cx
  1475.     mov temp,10        ; Divide quotient by 10.
  1476.     div temp        ; AX <-- Quo, DX <-- Rem.
  1477.     mov cx,dx        ; Remember the remainder.
  1478.     cmp ax,0        ; Are we done?    
  1479.     jz nout0x        ; Yes.
  1480.     mov dx,0
  1481.     call nout2        ; If not, then recurse.
  1482. nout0x:    add cl,'0'        ; Make it printable.
  1483.     mov temp,ax
  1484.     mov al,cl
  1485.     stosb
  1486.     mov ax,temp
  1487.     pop cx
  1488.     pop dx
  1489.     pop ax
  1490.     ret            ; We're done. [21c]
  1491. NOUT2X    ENDP
  1492.  
  1493. SPATH    proc    near
  1494. ; enter with ax/ ptr to file name.  Searches path for given file,
  1495. ; returns with ax/ ptr to whole name, or carry on if file isn't
  1496. ; to be found.
  1497.     push    es
  1498.     mov    bx,ds
  1499.     mov    es,bx            ; address data segment
  1500.     mov    bx,ax            ; convenient place to keep this
  1501.     call    isfile            ; does it exist as it is?
  1502.     mov    ax,bx            ; ifso, just return original name
  1503.     jc    spath0            ; nope...
  1504.     pop    es
  1505.     ret
  1506. spath0:    mov    si,ax
  1507.     mov    di,offset tfile        ; place to copy to
  1508.     mov    dl,0            ; no '\' seen yet
  1509. spath1:    lodsb
  1510.     stosb
  1511.     cmp    al,'/'            ; contain path characters?
  1512.     je    spath1a
  1513.     cmp    al,'\'
  1514.     jne    spath2            ; no, keep going
  1515. spath1a:mov    dl,1            ; remember we've seen them
  1516. spath2:    or    al,al
  1517.     jnz    spath1            ; copy name in
  1518.     or    dl,dl            ; look at flag
  1519.     jz    spath3            ; no path, keep looking
  1520.     jmp    spath9            ; embedded path, fail
  1521.  
  1522. spath3:    mov    si,offset pthbuf    ; path definition
  1523.     cmp    byte ptr [si],0        ; empty path?
  1524.     jne    spath4            ; no, keep going
  1525.     mov    ah,gcd            ; get current dir
  1526.     mov    dl,0            ; for default drive
  1527.     mov    si,offset defpth+1    ; place to put it
  1528.     int    dos
  1529.     mov    si,offset defpth    ; point to the path
  1530. spath4:    cmp    byte ptr [si],0        ; null, exit loop
  1531.     je    spath9
  1532.     mov    di,offset tfile        ; place to put name
  1533. spath5:    lodsb                ; get a byte
  1534.     cmp    al,';'            ; end of this part?
  1535.     je    spath7            ; yes, break loop
  1536.     cmp    al,0            ; maybe end of string?
  1537.     jne    spath6            ; no, keep going
  1538.     dec    si            ; back up over it
  1539.     jmp    short spath7        ; and break loop
  1540. spath6:    stosb                ; else stick in dest string
  1541.     jmp    spath5            ; and continue
  1542. spath7:    push    si            ; save this ptr
  1543.     mov    si,bx            ; this is user's file name
  1544.     cmp    byte ptr [di-1],'/'    ; does it end with switch char?
  1545.     je    spath8            ; yes, don't put one in
  1546.     mov    al,'\'            ; how about this one?
  1547.     cmp    byte ptr [di-1],al
  1548.     je    spath8            ; yes, don't put it in.
  1549.     stosb                ; else add one
  1550. spath8:    lodsb
  1551.     stosb
  1552.     or    al,al
  1553.     jnz    spath8            ; copy rest of name
  1554.     pop    si            ; restore pos in path def
  1555.     mov    ax,offset tfile
  1556.     call    isfile            ; is it a file?
  1557.     jc    spath4            ; no, keep looking
  1558.     mov    ax,offset tfile
  1559.     pop    es
  1560.     ret                ; return success (carry off)
  1561. spath9:    pop    es            ; restore this
  1562.     stc                ; no file found
  1563.     ret
  1564. spath    endp
  1565.  
  1566.  
  1567. isfile    proc    near
  1568. ; returns carry off if the file pointed to by ax exists
  1569.     mov    dx,ax            ; copy ptr
  1570.     mov    al,0            ; don't change anything
  1571.     mov    ah,chmod
  1572.     int    dos
  1573.     ret                ; dos sets carry
  1574. isfile    endp
  1575.  
  1576. ; initialize memory usage by returning to DOS anything past the end of kermit
  1577. memini    proc    near
  1578.     push    es
  1579.     mov    es,psp        ; address psp segment again
  1580.     mov    bx,offset msfinal + 15 ; end of pgm + roundup
  1581.     mov    cl,4
  1582.     shr    bx,cl        ; compute # of paragraphs in last segment
  1583.     mov    ax,seg datas    ; last segment
  1584.     sub    ax,psp        ; minus beginning
  1585.     add    bx,ax        ; # of paragraphs occupied
  1586.     mov    ah,setblk
  1587.     int    dos
  1588.      jc    memin1
  1589.     pop    es
  1590.     ret
  1591. memin1:    pop    es
  1592.     mov    dx,offset ermes2
  1593.     mov    ah,prstr
  1594.     int    dos        ; complain
  1595.     jmp    krmend        ; and just exit...
  1596. memini    endp
  1597.  
  1598. ; allocate memory.  Passed a memory size in ax, allocates that many
  1599. ; bytes (actually rounds up to a paragraph) at the end of the data
  1600. ; segment and returns the address of the new memory in ax.  The memory
  1601. ; is NOT initialized.
  1602. malloc    proc    near
  1603.     mov    bx,ax
  1604.     add    bx,15        ; round up
  1605.     mov    cl,4
  1606.     shr    bx,cl        ; convert to # of paragraphs
  1607.     mov    ah,alloc
  1608.     int    dos
  1609.     jc    mfatal        ; fatal to fail now...
  1610.     mov    bx,ds
  1611.     sub    ax,bx        ; compute offset in segment
  1612.     cmp    ax,1000h    ; too big?
  1613.     jae    mfatal        ; yup
  1614.     mov    cl,4
  1615.     shl    ax,cl        ; make into offset
  1616.     ret            ; and return
  1617. mfatal:    mov    dx,offset mfmsg
  1618.     mov    ah,prstr
  1619.     int    dos
  1620.     jmp    krmend
  1621. malloc    endp
  1622.  
  1623. ; Jumping to this location is like retskp.  It assumes the instruction
  1624. ;   after the call is a jmp addr.
  1625.  
  1626. RSKP    PROC    NEAR
  1627.     pop bp
  1628.     add bp,3
  1629.     push bp
  1630.     ret
  1631.  
  1632. RSKP    ENDP
  1633.  
  1634. ; Jumping here is the same as a ret.
  1635.  
  1636. R    PROC    NEAR
  1637.     ret
  1638. R    ENDP
  1639.  
  1640. code     ends            ; End of code section.
  1641.     end    start
  1642.